// 歌曲播放的数据共享文件
import { HYEventStore } from "hy-event-store"; // 导入 HYEventStore

// 导入封装的功能函数
// 1、parseLyric：解析歌词的功能函数
import { parseLyric } from "../hooks/index";

// 导入封装的网络接口
// 1、getSongDetail：获取歌曲详情的接口
// 2、getLyric：获取歌词的接口
import { getSongDetail, getLyric } from '../service/api_play';

// const audioContext = wx.createInnerAudioContext(); // 创建前台歌曲播放实例
const audioContext = wx.getBackgroundAudioManager(); // 创建后台播放实例

// 创建歌曲播放状态管理实例对象
const playerStore = new HYEventStore({
  state: {
    id: 0, // 当前歌曲的 id
    isFirstPlay: true, // 是否是第一次播放
    isStoping: false, // 当前是否是停止播放状态
    currentSong: {}, // 当前播放的歌曲数据

    lyricData: [], // 当前歌曲的歌词数据
    currentLyricIndex: 0, // 当前歌词数组的索引
    currentLyricText: "", // 当前时间点的歌词句

    currentTime: 0, // 当前播放的时长
    durationTime: 0, // 歌曲总时长

    playModeIndex: 0, // 播放模式：0 表示循环播放；1 表示单曲循环；2 表示随机播放
    isPlaying: false, // 播放状态，true 是播放；false 是暂停

    playSongsList: [], // 歌单列表
    playSongsIndex: 0, // 当前播放的歌曲在列表中的索引
  },
  actions: {
    // 获取歌曲数据的函数
    playMusicWithSongIdAction(ctx, { id, isRefresh = false }) {
      // 如果想要播放的歌曲的 id 和当前正在播放的歌曲的 id 一样，并且不重新刷新的话，就继续播放即可，后续操作不用继续
      if (ctx.id == id && !isRefresh) {
        this.dispatch("changeMusicPlayStateAction", true);
        return;
      }

      ctx.id = id; // 获取 id
      ctx.isPlaying = true; // 更改播放状态

      // 0、每次重新发送请求的时候，将前一首歌的数据清空
      ctx.currentSong = {};
      ctx.lyricData = [];
      ctx.currentLyricIndex = 0;
      ctx.currentLyricText = "";
      ctx.durationTime = 0;
      ctx.currentTime = 0;

      // 1、发送请求
      // 发送获取歌曲数据的接口请求
      getSongDetail(id).then(res => {
        ctx.currentSong = res.songs[0]; // 歌曲数据
        ctx.durationTime = res.songs[0].dt; // 歌曲时长
        audioContext.title = res.songs[0].name; // 歌曲的 title（wx.getBackgroundAudioManager API 必填属性）
      });

      // 发送获取歌词的接口请求
      getLyric(id).then(res => {
        const lyricString = res.lrc.lyric; // 获取歌词
        const lyrics = parseLyric(lyricString); // 解析歌词
        ctx.lyricData = lyrics;
      });

      // 2、播放对应 id 的歌曲
      audioContext.stop(); // 停止前一个歌曲
      audioContext.src = `https://music.163.com/song/media/outer/url?id=${id}.mp3`; // 设置播放地址
      audioContext.title = id; // 设置一下 title
      audioContext.autoplay = true; // 自动播放

      // 3、监听 audioContext 播放的事件
      if(ctx.isFirstPlay) {
        // 只有第一次播放，才添加事件监听
        this.dispatch("setupAudioContextLinsterAction");
        ctx.isFirstPlay = false;
      }

      // 4、监听英语播放/暂停/停止事件
      // 播放
      audioContext.onPlay(() => {
        ctx.isPlaying = true;
      });
      // 暂停
      audioContext.onPause(() => {
        ctx.isPlaying = false;
      });
      // 停止
      audioContext.onStop(() => {
        ctx.isPlaying = false;
        ctx.isStoping = true; // 更改停止播放状态
      });
    },

    // 歌曲播放处理的函数
    setupAudioContextLinsterAction(ctx) {
      // 1、监听歌曲的播放
      audioContext.onCanplay(() => {
        audioContext.play(); // 开始播放
      });
  
      // 2、监听时间的更新
      audioContext.onTimeUpdate(() => {
        // 1、获取当前播放的时间
        const currentTime = audioContext.currentTime * 1000;
  
        // 2、根据当前播放的时间设置 currentTime
        ctx.currentTime = currentTime;
  
        if(!ctx.lyricData.length) return; // 如果没有歌词就直接退出
  
        // 3、根据当前时间，查找时间点对应的歌词
        let i = 0;
        for (; i < ctx.lyricData.length; i++) {
          const lyricInfo = ctx.lyricData[i]; // 当前行的歌词数据
          // 如果当前时间点小于当前行的时间，就显示前一句歌词
          if(currentTime < lyricInfo.time) {
            break; // 找到了具体的歌词句，就退出
          } 
        }
  
        // 设置歌词的索引和内容
        const currentLyricIndex = i - 1; // 这个是我要找的当前时间点的歌词句的索引
  
        // 当索引值不同的时候，即歌词不一样的时候，才需要更新歌词
        if(ctx.currentLyricIndex !== currentLyricIndex) {
          const currentLyricInfo = ctx.lyricData[currentLyricIndex]; // 当前时间点的歌词句的信息
          ctx.currentLyricText = currentLyricInfo.lyricText;  // 当前播放的歌词内容
          ctx.currentLyricIndex = currentLyricIndex; // 当前播放歌词的索引号
        }
      });

      // 3、监听歌曲播放完成
      audioContext.onEnded(() => {
        // 当前歌曲播放完后，就调用下切换歌曲的方法
        this.dispatch("changeNewMusicAction");
      })
    },

    // 更改歌曲播放的状态
    changeMusicPlayStateAction(ctx, isPlaying = true) {
      console.log(ctx.currentSong);
      ctx.isPlaying = isPlaying;

      // 如果想让歌曲开始播放，但是同时是一个停止状态，那么就要重新给 audioContext 设置属性
      if(ctx.isPlaying && ctx.isStoping) {
        audioContext.src = `https://music.163.com/song/media/outer/url?id=${ctx.id}.mp3`; // 设置播放地址
        audioContext.title = ctx.currentSong.name; // 设置一下 title
        audioContext.startTime = ctx.currentTime / 1000; // 开始上一次停止的地方开始播放
        ctx.isStoping = false;
      }

      // 如果是播放状态，就播放歌曲;如果是暂停状态，就暂停歌曲
      ctx.isPlaying ? audioContext.play() : audioContext.pause();
    },

    // 切换歌曲的事件
    changeNewMusicAction(ctx, isNext = true) {
      // 1、获取当前歌曲的索引
      let currentIndex = ctx.playSongsIndex;

      // 2、根据不同的播放模式，获取下一首歌的索引
      switch (ctx.playModeIndex) {
        case 0: // 顺序播放
          // 判断当前是播放上一首还是下一首歌曲 
          currentIndex = isNext ? currentIndex + 1 : currentIndex - 1;

          // 想要播放第一首歌的上一首歌，就播放最后一首歌
          if(currentIndex === -1) currentIndex = ctx.playSongsList.length - 1;
          // 顺序播放完最后一首歌的时候，播放第一首歌
          if(currentIndex === ctx.playSongsList.length) currentIndex = 0;
          break;
        case 1: // 单曲循环
          break;
        case 2: // 随机播放
          currentIndex = Math.floor(Math.random() * ctx.playSongsList.length);

          // 如果当前随机到的索引和上一首歌一样，那么就再继续随机；并且歌曲列表的歌曲数不为 1
          while (currentIndex === ctx.playSongsIndex && ctx.playSongsList.length !== 1) {
            currentIndex = Math.floor(Math.random() * ctx.playSongsList.length);
          }
          break;
      }

      //3、获取当前要播放的歌曲
      let currentSong = ctx.playSongsList[currentIndex];
      // 如果要播放的歌曲不存在，那么就继续播放当前的歌曲
      if(!currentSong) {
        currentSong = ctx.currentSong;
      } else {
        // 播放新的歌曲，更新当前歌曲的索引
        ctx.playSongsIndex = currentIndex;
      }

      // 4、播放新的歌曲
      this.dispatch("playMusicWithSongIdAction", { id: currentSong.id, isRefresh: true });
    }
  }
});

// 导出
export {
  audioContext, // 创建歌曲播放实例
  playerStore // 歌曲播放状态管理实例对象
}
